import type { Mapless } from '..';
import type { IdHubType } from '../core/IdHub';
import IdHub from '../core/IdHub';
import { Manager } from '../core/manager';
import type { ManagerOptions, PolygonOptions } from '../index.d';

type ShapeIdHubType = IdHubType & {
  sourceId: string;
  fillLayerId: string;
  lineLayerId: string;
};

export default class ShapeManager extends Manager<ShapeIdHubType> {
  private shapes: Record<string, GeoJSON.GeoJSON> = {};

  constructor(mapless: Mapless, options?: ManagerOptions) {
    super(mapless, options, 'shape');
    this.onInitialized();
  }

  override createIdHub(_idHub?: IdHubType): void {
    const newHub = new IdHub({
      layers: {
        fillLayerId: 'dzmap-shape-fill-layer',
        lineLayerId: 'dzmap-shape-line-layer',
      },
      sources: {
        sourceId: 'dzmap-shape-source',
      },
    }) as ShapeIdHubType;
    super.createIdHub(newHub);
  }

  override initLayers() {
    if (!this.mapless) return;
    const sid = this.idHub?.sourceId;
    this.mapless.addEmptySource(sid);
    this.mapless.addLayer({
      id: this.idHub?.fillLayerId,
      type: 'fill',
      source: sid,
      paint: {
        'fill-color': ['get', 'fillColor'],
        'fill-opacity': ['get', 'fillOpacity'],
      },
    });
    this.mapless.addLayer({
      id: this.idHub?.lineLayerId,
      type: 'line',
      source: sid,
      paint: {
        'line-color': ['get', 'outlineColor'],
        'line-width': 2,
      },
    });
  }

  drawShape(id: string, options: PolygonOptions) {
    const {
      coordinates,
      fillColor = 'rgba(255,0,0,0.1)',
      fillOpacity = 1,
      outlineColor = 'rgba(250, 250, 250, 1)',
    } = options;
    const shape = {
      type: 'Feature' as const,
      geometry: {
        type: 'Polygon' as const,
        coordinates: [coordinates],
      },
      properties: { id, fillColor, fillOpacity, outlineColor },
    };
    this.shapes[id] = shape;
    this.mapless?.setData(this.idHub?.sourceId, {
      type: 'FeatureCollection',
      features: Object.values(this.shapes) as GeoJSON.Feature[],
    });
  }

  removeShape(id: string) {
    if (!this.map || !this.shapes[id]) return;
    delete this.shapes[id];
    this.mapless?.setData(this.idHub?.sourceId, {
      type: 'FeatureCollection',
      features: Object.values(this.shapes) as GeoJSON.Feature[],
    });
  }

  removeAll() {
    this.mapless?.setEmptyData(this.idHub?.sourceId);
    this.shapes = {};
  }

  override destroy() {
    super.destroy();
    this.shapes = {};
  }
}

export const attachShape = (mapless: Mapless | undefined, name?: string) =>
  mapless?.use(ShapeManager, name);
export const getShape = (mapless: Mapless | undefined, name?: string) =>
  mapless?.get(ShapeManager, name);
export const detachShape = (mapless: Mapless | undefined, name?: string) =>
  mapless?.unuse(ShapeManager, name);
